package cn.myframe.shiro;

import cn.myframe.utils.annotation.IgnoreAuth;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.web.bind.annotation.RequestMapping;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 
 * 查找使用@IgnoreAuth忽略shiro认证的URL
 * 
 * @author  ynz
 * @email   ynz@myframe.cn
 * @version 创建时间：2018年6月13日 下午12:05:07
 */
@Slf4j
public class IgnoreUrlUtils {
	
	/**
	 * 根据@IgnoreAuth,查询忽略认证的URL
	 * @param packageName 扫描包名
	 * @return
	 */
	public static List<String> findIgnoreUrl(String packageName ){
		List<String> urllist = new ArrayList<String>();
		try{
			List<String> packageList = scanPackage(packageName);
			packageList.forEach(className -> {
				try {
					Class<?> clz  = Class.forName(className);
					//判断类是否有@IgnoreAuth注解
					boolean isClassAnno =  clz.isAnnotationPresent(IgnoreAuth.class);
					if(isClassAnno){
						RequestMapping annotation = clz.getAnnotation(RequestMapping.class);
						//类的@RequestMapping注解
						String[] path = null;
						if(annotation != null){
							path = annotation.value();
						}
						String value =  clz.getAnnotation(IgnoreAuth.class).value();
						List<String> methodUrlList =  findMethodAnno(clz,value);
						buildTotalUrl( path,  methodUrlList,  urllist);
					}
				} catch (Exception e) {
					log.error(e.getMessage());
				}
				
			});
		}catch(Exception e){
			log.error(e.getMessage());
		}
		return urllist;
	}
	
	
	/**
	 * 扫描指包下的所有类 
	 * @param packageName   如果想扫描cn.rojao包下的类，输入cn/myframe
	 * @return
	 */
	private static List<String> scanPackage(String packageName){
		List<String> list = new ArrayList<String>();
		try{
			ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
			Resource[] resources = resourcePatternResolver.getResources("classpath*:"+packageName+"/**/*.class");
			if(resources != null){
				for(Resource resource : resources){
					String className = resource.getURL().getPath();
					int lastIndexOf = className.lastIndexOf(packageName);
					className = className.substring(lastIndexOf, className.length());
					className = className.replace("/", ".").replace(".class", "");
					list.add(className);
				}
			}
			
		}catch(Exception e){
			log.error(e.getMessage());
		}
		return list;
	}
	
	
	
	/**
	 * 查询类中方法的@RequestMapping
	 * @param clz
	 * @param type        type=ALL时,不判断方法是否有@IgnoreAuth
	 * @return
	 */
	public static List<String> findMethodAnno(Class<?> clz,String type){
		//类中的方法
		Method[] methods = clz.getDeclaredMethods();
		List<String> list = new ArrayList<>();
		if(methods != null){
			for(Method method : methods){
				//如果类为@IgnoreAuth("ALL"),不判断方法是否有@IgnoreAuth,只判断是否有@RequestMapping
				if(!type.toUpperCase().equals("ALL")){
					boolean ignoreMethodAnno = method.isAnnotationPresent(IgnoreAuth.class);
		            if(!ignoreMethodAnno){
		            	continue;
		            }
				}
				//判断方法是否有@RequestMapping
				RequestMapping requestMappingAnno = method.getAnnotation(RequestMapping.class);
				if(requestMappingAnno != null){
					String[] urls = requestMappingAnno.value();
					list.addAll(Arrays.asList(urls));
				}
			}
		}
		return list;
	}
	
	/**
	 * 生成完整的URL
	 * @param path
	 * @param methodUrlList
	 * @param urllist
	 */
	public static void buildTotalUrl(String[] path, List<String> methodUrlList, List<String> urllist){
		methodUrlList.forEach(methodUrl -> {
			if(path != null && path.length > 0){
				for(String pathUrl : path){
					urllist.add(pathUrl + methodUrl);
				}
			}else{
				urllist.add(methodUrl);
			}
		});
	}

}
